﻿using System;
using System.Windows;
using System.Collections.Generic;
using System.Windows.Controls;
using System.Windows.Media;
using Bling.DSL;
using Bling.WPF;
using Bling.Shapes;
using Bling.Animation;
using Bling.Util;

namespace Bling.Tutorial {
  public class BezierTest : Canvas {

    public BezierTest() {
      CanvasBl canvas = this;
      PointBl[] Points = new PointBl[9];
      PointBl[] Original = new PointBl[9];
      PointBl[] Thumbs = new PointBl[9];

      PathShapeBl shape = new PathShapeBl(canvas) {
        ZIndex = 0,
        Start = { Now = new PointBl(50, 50) },
        Fill = Brushes.LightPink,
        Stroke = { Brush = Brushes.Black, Thickness = 2 },
        OnMouseEnter = (x, y) => {
          foreach (var p in Thumbs) p.Stop(true);
          return true;
        },
      };
      ImageBl image = new ImageBl(canvas) {
        Source = Properties.Resources.Dock,
        LeftTop = new PointBl(55, 55), Size = new PointBl(400, 400),
        IsHitTestVisible = false, ZIndex = 1,
        Opacity = 0.2,
      };
      image.CurrentValue.Stretch = Stretch.Fill;

      SliderBl slider = new SliderBl(canvas) {
        Width = canvas.Width, RightBottom = canvas.Size,
        Minimum = 0, Maximum = 1, Value = .5,
      };


      {
        var i = 0;
        Points[0] = shape.Start;
        Points[8] = new PointBl(0, 0);
        for (int j = 0; j < 4; j++) {
          int sign = (j < 2) ? +1 : -1;
          OrientationBl orient = (j % 2 == 0) ? Orientation.Horizontal : Orientation.Vertical;

          var thumbA = Thumbs[i + 1] = new ThumbBl(canvas) {
            ZIndex = 3, Background = Brushes.Red, CanDrag = true,
            CenterPosition = { Now = Points[i] + PointBl.Make(orient, 200 * sign) },
          };
          var thumbB = Thumbs[(i + 2) % (Thumbs.Length - 1)] = new ThumbBl(canvas) {
            ZIndex = 3, Background = Brushes.Blue, CanDrag = true,
            CenterPosition = { Now = Points[i] + PointBl.Make(orient, 400 * sign) },
          };
          // loop around.
          QuadraticBezierSegmentBl segment = new QuadraticBezierSegmentBl() {
            Point2 = thumbB,
          };
          // assign the array.
          Points[(i + 1)] = segment.Point1;
          if (i + 2 == Points.Length - 1) shape.Start = thumbB;
          else Points[(i + 2)] = segment.Point2;

          var ratio = (thumbA - Points[i]).Select[orient] / ((segment.Point2 - thumbA).Select[orient] + (thumbA - Points[i]).Select[orient]);

          PointBl.Bezier(ratio, 1, Points[i], segment.Point1, segment.Point2).Bind = thumbA;
          shape.Segments.Add(segment);

          i += 2;
        }
        (i == Points.Length - 1).Assert();
      }
      Points[8] = (Points[0] + Points[2] + Points[4] + Points[6]) / 4.0;
      Thumbs[8] = new ThumbBl(canvas) {
        ZIndex = 3, Background = Brushes.Purple, CanDrag = true,
        CenterPosition = Points[8],
      };

      for (int i = 0; i < Points.Length; i++) {
        Original[i] = Thumbs[i].CurrentValue;
      }
      new ButtonBl(canvas) {
        RightBottom = slider.RightTop, Content = "ToSquare",
        Click = () => {
          for (int i = 0; i < Points.Length; i++)
            Thumbs[i].Animate.AutoReverse().Forever().Tween(t => t.Ease.Bounce.Out).To = Original[i];
        }
      };

      DoubleBl minX = Points[0].X;
      DoubleBl minY = Points[0].Y;

      DoubleBl maxX = Points[0].X;
      DoubleBl maxY = Points[0].Y;

      for (int i = 2; i < Points.Length - 1; i += 2) {
        // look at 0, 1, 2
        var q = PointBl.Bezier(.5, Points[i - 2], Points[i - 1], Points[i - 0]);

        minX = minX.Min(Points[i].X).Min(q.X);
        minY = minY.Min(Points[i].Y).Min(q.Y);
        maxX = maxX.Max(Points[i].X).Max(q.X);
        maxY = maxY.Max(Points[i].Y).Max(q.Y);
      }
      {
        var q = PointBl.Bezier(.5, Points[6], Points[7], Points[0]);
        minX = minX.Min(q.X);
        minY = minY.Min(q.Y);
        maxX = maxX.Max(q.X);
        maxY = maxY.Max(q.Y);
      }

      DoubleBl deltaX = maxX - minX;
      DoubleBl deltaY = maxY - minY;
      PointBl min = new PointBl(minX, minY);
      PointBl max = new PointBl(maxX, maxY);

      new ThumbBl(canvas) {
        ZIndex = 2, Background = Brushes.Purple, CenterPosition = new PointBl(maxX, maxY),
      };
      new ThumbBl(canvas) {
        ZIndex = 2, Background = Brushes.Pink, CenterPosition = new PointBl(minX, minY),
      };
      Func<PointBl, PointBl> Relative = (p) =>
        //        (p - shape.LeftTop) / shape.Size;
        (p - new PointBl(minX, minY)) / new PointBl(deltaX, deltaY);
      var effectCanvas = new CanvasBl(canvas) {
        ZIndex = 1, Opacity = 1, LeftTop = min, Size = max - min,
        Background = Properties.Resources.Dock,
      };
      Func<string, LabelBl> MkLabel = (nm) => {
        var ret = new LabelBl(effectCanvas) {
          Content = nm, Font = { Weight = FontWeights.SemiBold },
          Background = new SolidColorBrushBl() { Color = Colors.White, Opacity = 0.5 },
        };
        ret.Font.Size = ret.IsMouseOver.Condition(40, 20);
        ret.Font.Brush = ret.IsMouseOver.Condition(Brushes.Red, Brushes.Black);
        return ret;
      };
      MkLabel("Center").CenterPosition = effectCanvas.CenterSize;
      MkLabel("NorthWest").LeftTop = new PointBl(20, 20);
      MkLabel("NorthEast").RightTop = new PointBl(effectCanvas.Width-20, 20);
      MkLabel("SouthWest").LeftBottom = new PointBl(20, effectCanvas.Height-20);
      MkLabel("SouthEast").RightBottom = effectCanvas.Size-new PointBl(20,20);


      shape.Visibility = true;

      shape.Fill = new ImageBrushBl() { ImageSource = Properties.Resources.Dock };
      shape.Stroke.Thickness = 0d;
      var visualBrush = new VisualBrushBl() {
        Visual = shape,
      };
      PointBl[] ps = new PointBl[Points.Length];
      for (int i = 0; i < Points.Length; i++) ps[i] = Relative(Points[i]);

      effectCanvas.Effect.CustomWithMap = (input, uv) => {

        //return ColorBl.FromScRgb(input[uv].ScA, brush[uv].ScRGB * input[uv].ScA);
        //uv = uv.Distort(p0, p2, p4, p6);

        PointBl right = PointBl.Bezier(uv.Y, ps[2], ps[3], ps[4]);
        PointBl left = PointBl.Bezier(1d - uv.Y, ps[6], ps[7], ps[0]);

        PointBl top = PointBl.Bezier(uv.X, ps[0], ps[1], ps[2]);
        PointBl bot = PointBl.Bezier(1d - uv.X, ps[4], ps[5], ps[6]);

        DoubleBl newX = (uv - left).Length / ((uv - right).Length + (uv - left).Length);
        DoubleBl newY = (uv - top).Length / ((bot - uv).Length + (uv - top).Length);
        return ColorBl.FromScRGB(1d, input[new PointBl(newX, newY)].ScRGB) * visualBrush[uv].ScA;
      };
      //1:
      //var right = PointBl.Bezier(uv.Y, p2, Relative(Points[3]), p4);
      //var left = PointBl.Bezier(1.0 - uv.Y, p6, Relative(Points[7]), p0);

      //var top = PointBl.Bezier(uv.X, p0, Relative(Points[1]), p2);
      //var bot = PointBl.Bezier(1 - uv.X, p4, Relative(Points[5]), p6);

      //var newX = (uv.X - left.X) / (right.X - left.X);
      //var newY = (uv.Y - top.Y) / (bot.Y - top.Y);
      //return ColorBl.FromScRgb(input[uv].ScA, brush[new PointBl(newX, newY)].ScRGB * input[uv].ScA);

      //2:
      //var right = PointBl.Bezier(uv.Y, p2, Relative(Points[3]), p4);
      //var left = PointBl.Bezier(1.0 - uv.Y, p6, Relative(Points[7]), p0);
      //var mid = PointBl.Bezier(uv.Y, Relative(Points[1]), Relative(Points[8]), Relative(Points[5]));

      //var newXY = PointBl.Bezier(1.0 - uv.X, right, mid, left);       
      //return ColorBl.FromScRgb(input[uv].ScA, brush[newXY].ScRGB * input[uv].ScA);

    }
  }

}
